<?php
/**
 * crcl/base
 *
 * Copyright 2013 CRCL - André Sabosch - info@crcl.de
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace crcl\base\mvc;

interface IResolver
{
  /**
   * Executes command
   *
   * @param \crcl\base\mvc\ICommand $oCommand
   */
  public function execute(\crcl\base\mvc\ICommand $oCommand);
}

class Resolver implements IResolver
{
  public function execute(\crcl\base\mvc\ICommand $oCommand)
  {
    $sFile = $this->getControllerFile($oCommand);
    $sClass = $oCommand->getControllerWithNamespace();
    $sAction = $oCommand->getActionWithMethod();
    $this->checkFile($sFile);
    $this->checkClass($sFile, $sClass);

    $oController = new $sClass();
    $this->checkParent($oController, $sClass);
    $this->checkAction($oController, $sAction, $sClass);

    $oController->setCommand($oCommand);

    $oController->onPreAction();
    $oController->$sAction();

    //$oController->eventPostAction();

    $oCommand = $oController->getCommand();
    return $oCommand;
  }

  /** PRIVATE *************************************************************************************/

  private function getControllerFile(\crcl\base\mvc\ICommand $oCommand)
  {
    $sDirectory = \crcl\base\application\Path::getDirectory(
      \crcl\base\application\Path::DIR_CONTROLLER);

//    if ($oCommand->hasVersion())
//    {
//      $sDirectory .= $oCommand->getVersion() . '/';
//    }
    if ($oCommand->hasGroup())
    {
      $sDirectory .= $oCommand->getGroup() . '/';
    }
    $sFile = $sDirectory . $oCommand->getController() . '.php';

    return $sFile;
  }

  private function checkFile($sFile)
  {
    if (!\file_exists($sFile))
    {
      throw new Exception('File does not exist',
        Exception::ERROR_RESOLVER_NOFILE, array('file' => $sFile));
    }
  }

  private function checkClass($sFile, $sClass)
  {
    if (!\class_exists($sClass))
    {
      throw new Exception(
        'Class does not exist',
        Exception::ERROR_RESOLVER_NOCLASS,
        array('file' => $sFile, 'class' => $sClass));
    }
  }

  private function checkAction(\crcl\base\mvc\controller\IConcrete $oController, $sAction, $sClass)
  {
    if (!\method_exists($oController, $sAction))
    {
      throw new Exception(
        'Action does not exist',
        Exception::ERROR_RESOLVER_NOACTION,
        array('action' => $sAction, 'class' => $sClass));
    }
  }

  private function checkParent($oController, $sClass)
  {
    if (!\is_subclass_of($oController, '\crcl\base\mvc\controller\IConcrete'))
    {
      throw new Exception(
        'Wrong parent',
        Exception::ERROR_RESOLVER_WRONGPARENT,
        array('class' => $sClass, 'parent' => \get_parent_class($oController)));
    }
  }
}